using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.IO;
using System.Threading.Tasks;
using GrapeCity.Forguncy.Commands;
using GrapeCity.Forguncy.Plugin;
using iTextSharp.text;
using iTextSharp.text.pdf;

namespace PdfOperationCommand
{
    [Icon("pack://application:,,,/PdfOperationCommand;component/Resources/Split.png")]
    [OrderWeight(3)]
    [Description("拆分PDF文件，使用iTextSharp实现")]
    public class PdfDismemberServerCommand : BaseServerCommand, ICommandExecutableInServerSideAsync
    {
        [Required]
        [FormulaProperty]
        [DisplayName("文件路径")]
        [Description("文件绝对路径，如：D:\\example.pdf(Windows)，/path/example.pdf(Linux)")]
        public object FilePath { get; set; }

        [DisplayName("PDF文件拆分类型")]
        [Description("PDF文件拆分类型")]
        public PdfSplitType PdfSplitType { get; set; }

        [DisplayName("拆分范围")]
        [Description("PDF文件拆分范围，比如输入1-5，则会将PDF的1-5页拆分成一个文件")]
        [ListProperty(MinCount = 1)]
        public List<PdfSplitRange> PdfPageRanges { get; set; }

        [IntProperty(Min = 1)]
        [DisplayName("固定范围")]
        [Description("PDF文件固定拆分范围，比如输入5，则会将PDF文件从头开始每5也拆分成一个文件")]
        public int FixedPage { get; set; } = 1;

        [Required]
        [FormulaProperty]
        [DisplayName("输出文件目录")]
        [Description("文件目录绝对路径，如：D:\\example(Windows)，/path/example(Linux)")]
        public object OutFileDir { get; set; }

        public async Task<ExecuteResult> ExecuteAsync(IServerCommandExecuteContext dataContext)
        {
            var filePath = await GetParamValue(dataContext, FilePath);
            var outFileDir = await GetParamValue(dataContext, OutFileDir);

            using var reader = new PdfReader(filePath.ToString());
            var fileName = Path.GetFileNameWithoutExtension(filePath.ToString());
            var pageCount = reader.NumberOfPages;
            if (PdfSplitType == PdfSplitType.CustomRange)
            {
                for (var i = 1; i <= PdfPageRanges.Count; i++)
                {
                    var pageRange = PdfPageRanges[i - 1];
                    var outFilePath = GeneratePath(outFileDir.ToString(), fileName, i);
                    var start = pageRange.StartPage;
                    var end = pageRange.EndPage > pageCount ? pageCount : pageRange.EndPage;
                    SplitPdf(reader, start, end, outFilePath);
                }
            }
            else
            {
                var count = (pageCount + FixedPage - 1) / FixedPage;
                for (var i = 1; i <= count; i++)
                {
                    var outFilePath = GeneratePath(outFileDir.ToString(), fileName, i);
                    var start = (i - 1) * FixedPage + 1;
                    var end = i * FixedPage > pageCount ? pageCount : i * FixedPage;
                    SplitPdf(reader, start, end, outFilePath);
                }
            }

            return new ExecuteResult();
        }

        private string GeneratePath(string outFileDir, string fileName, int index)
        {
            return outFileDir + Path.DirectorySeparatorChar + fileName + "_" + index + ".pdf";
        }

        private void SplitPdf(PdfReader pdfReader, int start, int end, string outFilePath)
        {
            using (var document = new Document())
            {
                using (var copy = new PdfCopy(document, new FileStream(outFilePath, FileMode.Create)))
                {
                    document.Open();
                    for (var j = start; j <= end; j++)
                    {
                        var page = copy.GetImportedPage(pdfReader, j);
                        copy.AddPage(page);
                    }
                }
            }
        }

        public override bool GetDesignerPropertyVisible(string propertyName, CommandScope commandScope)
        {
            if (propertyName == nameof(PdfPageRanges))
            {
                return PdfSplitType == PdfSplitType.CustomRange;
            }

            if (propertyName == nameof(FixedPage))
            {
                return PdfSplitType == PdfSplitType.FixedRange;
            }

            return base.GetDesignerPropertyVisible(propertyName, commandScope);
        }

        public override string ToString()
        {
            return "拆分PDF文件";
        }
    }
    
    public enum PdfSplitType
    {
        [Description("自定义范围")] CustomRange,
        [Description("固定范围")] FixedRange,
    }
    
    public partial class PdfSplitRange
    {
        [Description("起始页")]
        [IntProperty(Min = 1)]
        public int StartPage { get; set; }

        [Description("截止页")]
        [IntProperty(Min = 1)]
        public int EndPage { get; set; }
    }
}
